package managers

import (
	"errors"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"myself/exceptions"
	"reflect"
)

func InitDb() (*gorm.DB, error) {
	var db *gorm.DB
	var err error
	db, err = gorm.Open("mysql", "debian-sys-maint:1pNsU5XWWEZkAnae@tcp(175.178.27.172:3306)/wiki_database?charset=utf8&parseTime=True")
	if err != nil {
		fmt.Println("数据库连接错误", err)
		return nil, err
	}
	db.LogMode(true)
	db.SingularTable(true)
	return db, nil
}

type BaseManager struct {
	Conn  *gorm.DB
	Model interface{}
}

// SetConn 设置数据库连接
func (bm *BaseManager) SetConn(conn *gorm.DB) {
	bm.Conn = conn
}

// SetModel 设置 manager 对应的 model
func (bm *BaseManager) SetModel(model interface{}) {
	bm.Model = model
}

// GetNewModel 获取新的struct，返回值 *struct{}
func (bm *BaseManager) GetNewModel() interface{} {
	model := reflect.TypeOf(bm.Model).Elem()
	return reflect.Indirect(reflect.New(model)).Addr().Interface()
}

// GetCount 查询记录数
func (bm *BaseManager) GetCount(condition Condition) (int64, error) {
	var count int64

	querySet := bm.Conn
	if condition.FilterQuery != "" {
		querySet = querySet.Where(condition.FilterQuery, condition.FilterArgs...)
	}
	if condition.FilterMap != nil {
		querySet = querySet.Where(condition.FilterMap)
	}
	model := bm.GetNewModel()
	err := querySet.Model(model).Count(&count).Error
	if err != nil {
		return 0, exceptions.NewInterError(err.Error())
	}
	return count, nil
}

// GetById 根据主键查询信息
func (bm BaseManager) GetById(modelId uint32) (interface{}, error) {
	model := bm.GetNewModel()
	err := bm.Conn.Where("id = ?", modelId).First(model).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, exceptions.NewInterError(err.Error())
	}

	// 未找到记录的话，不算报错
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}

	return model, nil
}

// Create 创建记录 传入Model结构体类型的数据
func (bm BaseManager) Create(modelInfo interface{}) (interface{}, error) {
	result := bm.Conn.Create(modelInfo)
	err := result.Error
	if err != nil {
		return nil, exceptions.NewInterError(fmt.Sprintf("创建失败：%s", err))
	}
	return modelInfo, nil
}

// UpdateById 根据ID来修改信息
// updateInfo 要更新的信息
// @return 影响行数
func (bm BaseManager) UpdateById(modelId uint32, updateInfo map[string]interface{}) (int64, error) {
	model := bm.GetNewModel()
	result := bm.Conn.Model(model).Where("id = ?", modelId).Updates(updateInfo)
	err := result.Error
	if err != nil {
		return 0, exceptions.NewInterError(fmt.Sprintf("更新失败：%s", err))
	}
	return result.RowsAffected, nil
}
